const express = require('express');
const http = require('http');
const { Server } = require('socket.io');
const cors = require('cors');

const app = express();
app.use(cors());

const server = http.createServer(app);
const io = new Server(server, {
  cors: {
    origin: '*',
    methods: ['GET', 'POST']
  },
  pingTimeout: 60000, // 延长超时时间
  pingInterval: 25000 // 设置心跳包间隔
});

// 存储活跃用户
const activeUsers = {};

// 记录socket id与用户id的映射
const socketToUser = {};

// 记录连接计数（调试用）
let connectionCount = 0;

// 用户处理函数
function addUserToRoom(socket, roomId, userId) {
  // 将socket id与用户id关联
  socketToUser[socket.id] = { userId, roomId };
  
  // 加入Socket.io房间
  socket.join(roomId);
  
  // 确保房间存在，不存在则创建
  if (!activeUsers[roomId]) {
    activeUsers[roomId] = [];
    console.log(`创建新房间: ${roomId}`);
  }
  
  // 检查用户是否已在房间中（防止重复添加）
  const userExists = activeUsers[roomId].some(user => user.userId === userId);
  if (!userExists) {
    // 添加用户到房间
    activeUsers[roomId].push({ userId, socketId: socket.id, joinTime: Date.now() });
    
    // 确保其他用户在房间中有足够时间接收新用户的加入通知
    setTimeout(() => {
      // 通知房间内其他用户有新用户加入
      socket.to(roomId).emit('user-connected', userId);
      
      console.log(`发送用户连接通知: ${userId} 加入了房间 ${roomId}`);
    }, 1000); // 延迟1秒发送通知
    
    // 通知新用户关于房间内现有的其他用户
    const otherUsers = activeUsers[roomId].filter(user => user.userId !== userId);
    if (otherUsers.length > 0) {
      const otherUserIds = otherUsers.map(user => user.userId);
      console.log(`向用户 ${userId} 发送现有用户列表:`, otherUserIds);
      
      // 短暂延迟后发送现有用户列表，确保客户端准备好接收
      setTimeout(() => {
        socket.emit('existing-users', otherUserIds);
      }, 2000); // 延迟2秒发送现有用户列表
    } else {
      console.log(`房间 ${roomId} 中没有其他用户`);
    }
    
    console.log(`用户 ${userId} (${socket.id}) 已加入房间 ${roomId}`);
    logRoomStatus(roomId);
  } else {
    console.log(`用户 ${userId} 已存在于房间 ${roomId} 中，跳过添加操作`);
    
    // 尽管用户已存在，仍然发送现有用户列表（可能是用户刷新页面）
    const otherUsers = activeUsers[roomId].filter(user => user.userId !== userId);
    if (otherUsers.length > 0) {
      const otherUserIds = otherUsers.map(user => user.userId);
      socket.emit('existing-users', otherUserIds);
    }
  }
}

// 将用户从房间移除
function removeUserFromRoom(socket, sendNotification = true) {
  // 查找用户信息
  const userInfo = socketToUser[socket.id];
  if (!userInfo) {
    console.log(`未找到与socket ${socket.id} 相关联的用户信息`);
    return;
  }
  
  const { userId, roomId } = userInfo;
  
  // 从房间中移除该用户，判断房间是否存在
  if (activeUsers[roomId]) {
    // 找到用户下标
    const userIndex = activeUsers[roomId].findIndex(user => 
      user.socketId === socket.id || user.userId === userId
    );
    
    if (userIndex !== -1) {
      // 移除用户
      activeUsers[roomId].splice(userIndex, 1);
      
      // 通知房间内其他用户该用户已断开连接
      if (sendNotification) {
        console.log(`通知房间 ${roomId} 中的其他用户: ${userId} 已断开连接`);
        socket.to(roomId).emit('user-disconnected', userId);
      }
      
      console.log(`用户 ${userId} (${socket.id}) 已从房间 ${roomId} 移除`);
      logRoomStatus(roomId);
      
      // 如果房间为空，则删除该房间
      if (activeUsers[roomId].length === 0) {
        delete activeUsers[roomId];
        console.log(`房间 ${roomId} 已被删除（空房间）`);
      }
    } else {
      console.log(`在房间 ${roomId} 中未找到用户 ${userId} (${socket.id})`);
    }
  } else {
    console.log(`房间 ${roomId} 不存在`);
  }
  
  // 清理映射
  delete socketToUser[socket.id];
  
  // 离开Socket.io房间
  if (roomId) {
    socket.leave(roomId);
  }
}

// 打印房间信息、房间内的用户信息
function logRoomStatus(roomId) {
  if (activeUsers[roomId]) {
    console.log(`房间 ${roomId} 当前用户 (${activeUsers[roomId].length}):`, 
      activeUsers[roomId].map(user => `${user.userId} (${user.socketId})`).join(', '));
  }
}

// 转发信令给特定用户的函数
function forwardSignalToUser(socket, type, data, roomId, fromUserId, toUserId) {
  // 找到房间信息
  if (!activeUsers[roomId]) {
    console.log(`房间 ${roomId} 不存在，无法发送 ${type}`);
    return;
  }
  
  if (toUserId) {
    // 找到特定用户信息，直接发送给特定用户
    const targetUser = activeUsers[roomId]?.find(user => user.userId === toUserId);
    if (targetUser) {
      console.log(`向特定用户 ${toUserId} (${targetUser.socketId}) 发送 ${type}`);
      // io.to(xxx)，给to里边的io连接发送消息
      io.to(targetUser.socketId).emit(type, data, fromUserId, toUserId);
    } else {
      console.log(`目标用户 ${toUserId} 不在房间中，无法发送 ${type}`);
      // 通知发送者目标用户不可用
      socket.emit('signal-error', { type, toUserId, error: 'user-not-found' });
    }
  } else {
    // 广播给房间内所有其他用户
    console.log(`向房间 ${roomId} 的所有其他用户广播 ${type}`);
    socket.to(roomId).emit(type, data, fromUserId);
  }
}

// 定义信令服务器事件
io.on('connection', (socket) => {
  connectionCount++;
  console.log(`新连接: ${socket.id} (总连接数: ${connectionCount})`);
  
  // 用户加入房间
  socket.on('join-room', (roomId, userId) => {
    if (!roomId || !userId) {
      console.log(`无效的房间ID或用户ID: roomId=${roomId}, userId=${userId}`);
      return;
    }
    
    console.log(`用户 ${userId} 请求加入房间 ${roomId}`);
    
    // 如果用户已经在其他房间，先将其移除
    if (socketToUser[socket.id]) {
      const { roomId: oldRoomId, userId: oldUserId } = socketToUser[socket.id];
      console.log(`用户 ${oldUserId} 已在房间 ${oldRoomId} 中，先移除`);
      removeUserFromRoom(socket, false);
    }
    
    // 将用户添加到新房间
    addUserToRoom(socket, roomId, userId);
  });
  
  // 用户主动请求获取房间用户列表
  socket.on('request-users', (roomId) => {
    // 获取用户信息
    const userInfo = socketToUser[socket.id];
    // 只能获取自己房间的用户列表
    if (!userInfo || userInfo.roomId !== roomId) {
      console.log(`无效的请求用户列表: socket=${socket.id}, roomId=${roomId}`);
      return;
    }
    
    console.log(`用户 ${userInfo.userId} 请求房间 ${roomId} 的用户列表`);
    
    // 检查房间是否存在
    if (!activeUsers[roomId]) {
      console.log(`请求的房间 ${roomId} 不存在`);
      return;
    }
    
    // 获取房间内的所有其他用户
    const otherUsers = activeUsers[roomId]
      .filter(user => user.userId !== userInfo.userId)
      .map(user => user.userId);
    
    console.log(`向用户 ${userInfo.userId} 发送房间 ${roomId} 的用户列表:`, otherUsers);
    
    // 发送用户列表
    socket.emit('existing-users', otherUsers);
    
    // 向其他用户广播这个用户的存在，防止之前的通知丢失
    setTimeout(() => {
      socket.to(roomId).emit('user-connected', userInfo.userId);
    }, 1000);
  });
  
  // 用户主动离开房间
  socket.on('leave-room', (roomId, userId) => {
    console.log(`用户 ${userId} 请求离开房间 ${roomId}`);
    removeUserFromRoom(socket);
  });

  // 处理offer信令
  socket.on('offer', (offer, roomId, fromUserId, toUserId) => {
    console.log(`从用户 ${fromUserId} 到用户 ${toUserId || '全部'} 的offer信令`);
    forwardSignalToUser(socket, 'offer', offer, roomId, fromUserId, toUserId);
  });

  // 处理answer信令
  socket.on('answer', (answer, roomId, fromUserId, toUserId) => {
    console.log(`从用户 ${fromUserId} 到用户 ${toUserId || '全部'} 的answer信令`);
    forwardSignalToUser(socket, 'answer', answer, roomId, fromUserId, toUserId);
  });

  // 处理ICE候选信息
  socket.on('ice-candidate', (candidate, roomId, fromUserId, toUserId) => {
    console.log(`从用户 ${fromUserId} 到用户 ${toUserId || '全部'} 的ICE候选信息`);
    forwardSignalToUser(socket, 'ice-candidate', candidate, roomId, fromUserId, toUserId);
  });
  
  // 用户断开连接
  socket.on('disconnect', () => {
    connectionCount--;
    console.log(`连接断开: ${socket.id} (剩余连接数: ${connectionCount})`);
    removeUserFromRoom(socket);
  });
  
  // 处理错误
  socket.on('error', (error) => {
    console.error(`Socket ${socket.id} 发生错误:`, error);
  });
  
  // 发送初始化确认信息
  socket.emit('server-info', { 
    message: 'Connection established with signaling server',
    socketId: socket.id,
    timestamp: Date.now()
  });
});

// 周期性检查活跃房间，移除异常断开但未正确清理的用户
setInterval(() => {
  console.log('执行周期性房间清理...', io.sockets);
  
  // 获取所有连接的socket ID
  const connectedSockets = Array.from(io.sockets.sockets.keys());
  
  // 检查每个房间
  for (const roomId in activeUsers) {
    // 获取房间的用户数组
    const room = activeUsers[roomId];
    const initialCount = room.length;
    
    // 过滤出仍然连接的用户
    const stillConnected = room.filter(user => connectedSockets.includes(user.socketId));
    
    // 如果有用户被移除，更新房间
    if (stillConnected.length < initialCount) {
      const removed = room.filter(user => !connectedSockets.includes(user.socketId));
      
      console.log(`从房间 ${roomId} 清理了 ${removed.length} 个断开连接的用户:`);
      removed.forEach(user => {
        console.log(`- ${user.userId} (${user.socketId})`);
        
        // 通知房间其他用户该用户已断开
        io.to(roomId).emit('user-disconnected', user.userId);
      });
      
      // 更新房间
      activeUsers[roomId] = stillConnected;
      
      // 如果房间为空，删除它
      if (stillConnected.length === 0) {
        delete activeUsers[roomId];
        console.log(`房间 ${roomId} 已被删除（空房间）`);
      }
    }
  }
}, 60000); // 每分钟执行一次

// 定时打印活跃房间信息（调试用）
setInterval(() => {
  const roomCount = Object.keys(activeUsers).length;
  if (roomCount > 0) {
    console.log(`当前活跃房间数: ${roomCount}`);
    for (const roomId in activeUsers) {
      console.log(`房间 ${roomId}: ${activeUsers[roomId].length} 个用户`);
      activeUsers[roomId].forEach(user => {
        console.log(`  - ${user.userId} (${user.socketId}), 加入时间: ${new Date(user.joinTime).toLocaleString()}`);
      });
    }
  } else {
    console.log('当前没有活跃房间');
  }
}, 30000); // 每30秒打印一次

const PORT = process.env.PORT || 5000;
server.listen(PORT, () => {
  console.log(`信令服务器已启动，监听端口 ${PORT}`);
}); 